package ru.ifmo.rybakov.muclumon.msvs.proxy;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.ifmo.rybakov.muclumon.ITaskListener;
import ru.ifmo.rybakov.muclumon.TaskObserver;

public class MSVSProxyPollingDaemon implements Runnable, ITaskListener {
	
	private static final Logger logger = LoggerFactory.getLogger(MSVSProxyPollingDaemon.class);
	
	private Boolean stopper = false;
	private Thread thread;
	
	private DateTime lastNodeStateRevision;
//	private DateTime lastTaskStateRevision;
	
	private Integer nodePollTimeout = 5;
//	private Integer taskPollTimeout = 1;
	
	private final MSVSProxyClient msvsProxyClient = new MSVSProxyClient();
	
	public MSVSProxyPollingDaemon() {
		TaskObserver.getInstance().addListener(this);
		logger.info("Subscribed to task observer");
		lastNodeStateRevision = new DateTime().minusMinutes(nodePollTimeout);
//		lastTaskStateRevision = new DateTime().minusMinutes(taskPollTimeout);
	}
	
	private Integer activeTasks = 0;
	
	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		
		// build first time configuration snapshot
		logger.info("First time run, building configuration snapshot");
		msvsProxyClient.buildConfigurationSnapshot(MSVSProxyClient.INTEGRATOR_URL);
		
		logger.info("Begin state snapshot building cycle, interval = {}m", nodePollTimeout);
		while (!stopper) {
			try {
				Thread.sleep(1000);
				if (activeTasks == 0) {
					continue; // do nothing, when no tasks actually running
				}
				// check if it is time to run new poll step
				DateTime now = new DateTime();
				if (now.minusMinutes(nodePollTimeout).isAfter(lastNodeStateRevision)) {
					// time to poll nodes
					msvsProxyClient.buildStateSnapshot(MSVSProxyClient.INTEGRATOR_URL);
					lastNodeStateRevision = now;
				}
				// DO NOT POLL TASKS DUE TO BUGS IN INTEGRATOR
//				if (now.minusMinutes(taskPollTimeout).isAfter(lastTaskStateRevision)) {
//					// time to poll tasks
//					msvsProxyClient.buildTaskStateSnapshot(MSVSProxyClient.INTEGRATOR_URL);
//					lastTaskStateRevision = now;
//				}
			} catch (InterruptedException e) {
				logger.error("Unexpected exception", e);
			}
		}
	}
	
	public void start() {
		logger.debug("Starting up daemon thread...");
		if (thread != null && thread.isAlive()) {
			logger.warn("Can't start daemon when it is already running");
			return;
		} else {
			stopper = false;
			thread = new Thread(this);
			thread.start();
			logger.info("Daemon thread was successfully started");
		}
	}
	
	public void stop() {
		logger.debug("Stopping daemon thread...");
		try {
			stopper = true;
			thread.join();
			logger.info("Daemon thread was successfully stopped");
		} catch (InterruptedException e) {
			logger.error("Thread join() was unexpectedly interrupted", e);
		}
	}

	/* (non-Javadoc)
	 * @see ru.ifmo.rybakov.muclumon.ITaskListener#onTaskStarted()
	 */
	@Override
	public synchronized void onTaskStarted() {
		lastNodeStateRevision = new DateTime().minusMinutes(nodePollTimeout + 1); // initiate state
		activeTasks++;
		logger.debug("Task started, active tasks: {}", activeTasks);
	}

	/* (non-Javadoc)
	 * @see ru.ifmo.rybakov.muclumon.ITaskListener#onTaskStopped()
	 */
	@Override
	public synchronized void onTaskStopped() {
		// lastNodeStateRevision = new DateTime().minusMinutes(nodePollTimeout + 1); // initiate state
		if (activeTasks > 0) {
			activeTasks--;
		}
		logger.debug("Task stopped, active tasks: {}", activeTasks);
	}
}
